﻿using System;
using System.Diagnostics;

namespace Microsoft.Popfly.GameCreator.GameEngine.Events
{
    public class PropertyCondition
    {
        public enum ConditionType
        {
            EQUALS,
            NOTEQUALS,
            GREATERTHAN,
            LESSTHAN,
            GREATERTHANOREQUAL,
            LESSTHANOREQUAL
        }
        private String m_propertyName;
        private ConditionType m_condition;
        private String m_stringValue;
        private PropertyHolder m_owner;

        public PropertyCondition(PropertyHolder owner, String propertyName, ConditionType conditionType)
        {
            m_owner = owner;
            m_propertyName = propertyName;
            m_condition = conditionType;
        }

        public PropertyCondition(PropertyHolder owner, Game game, Data.PropertyConditionInfo conditionInfo)
        {
            m_owner = owner;

            m_propertyName = conditionInfo.Name;
            m_stringValue = conditionInfo.Value;
            switch (conditionInfo.propertyCondition)
            {
                case Data.PropertyConditionInfo.Condition.Equals:
                    m_condition = ConditionType.EQUALS;
                    break;
                case Data.PropertyConditionInfo.Condition.GreaterThan:
                    m_condition = ConditionType.GREATERTHAN;
                    break;
                case Data.PropertyConditionInfo.Condition.GreaterThanOrEqual:
                    m_condition = ConditionType.GREATERTHANOREQUAL;
                    break;
                case Data.PropertyConditionInfo.Condition.LessThan:
                    m_condition = ConditionType.LESSTHAN;
                    break;
                case Data.PropertyConditionInfo.Condition.LessThanOrEqual:
                    m_condition = ConditionType.LESSTHANOREQUAL;
                    break;
                case Data.PropertyConditionInfo.Condition.NotEquals:
                    m_condition = ConditionType.NOTEQUALS;
                    break;
                default:
                    throw new NotImplementedException(Utils.ErrorMessagePrefix + "We don't handle that PropertyConditionInfo.Condition in PropertyCondition yet.");
            }
            m_owner = owner;

            string gamePrefix = "Game: ";
            if (m_propertyName.StartsWith(gamePrefix))
            {
                m_owner = game;

                m_propertyName.Remove(0, gamePrefix.Length);
            }

            if (conditionInfo.Reference == "Game")
            {
                m_owner = game;
            }
        }

        public bool CheckCondition(string compareAgainst)
        {
            m_stringValue = compareAgainst;
            return CheckCondition();
        }

        public bool CheckCondition()
        {
            Object value = m_owner.GetValue(m_propertyName);

            Type valueType = value.GetType();

            if (valueType.Equals(typeof(string)))
            {
                switch (m_condition)
                {
                    case ConditionType.EQUALS :
                        return m_stringValue.Equals((string)value);
                    case ConditionType.NOTEQUALS :
                        return !m_stringValue.Equals((string)value);
                        // TODO: Add in less than greater than...
                    default :
                        throw new NotImplementedException(Utils.ErrorMessagePrefix + "Only 'equals' and 'not equals' are supported unless the property value is a number.");
                }
            }
            else if (valueType.Equals(typeof(int)))
            {
                int parsedValue;
                bool intParsed = int.TryParse(m_stringValue, out parsedValue);
                double parsedDoubleValue = 0.0;
                bool doubleParsed = false;

                if (intParsed == false)
                {
                    doubleParsed = double.TryParse(m_stringValue, out parsedDoubleValue);
                }
                switch (m_condition)
                {
                    case ConditionType.EQUALS :
                        if (intParsed)
                        {
                            return ((int)value) == parsedValue;
                        }
                        else
                        {
                            if (doubleParsed)
                            {
                                return ((int)value) == parsedDoubleValue;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    case ConditionType.GREATERTHAN :
                        if (intParsed)
                        {
                            return ((int)value) > parsedValue;
                        }
                        else
                        {
                            if (doubleParsed)
                            {
                                return ((int)value) > parsedDoubleValue;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    case ConditionType.GREATERTHANOREQUAL :
                        if (intParsed)
                        {
                            return ((int)value) >= parsedValue;
                        }
                        else
                        {
                            if (doubleParsed)
                            {
                                return ((int)value) >= parsedDoubleValue;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    case ConditionType.LESSTHAN :
                        if (intParsed)
                        {
                            return ((int)value) < parsedValue;
                        }
                        else
                        {
                            if (doubleParsed)
                            {
                                return ((int)value) < parsedDoubleValue;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    case ConditionType.LESSTHANOREQUAL :
                        if (intParsed)
                        {
                            return ((int)value) <= parsedValue;
                        }
                        else
                        {
                            if (doubleParsed)
                            {
                                return ((int)value) <= parsedDoubleValue;
                            }
                            else
                            {
                                return false;
                            }
                        }
                    case ConditionType.NOTEQUALS:
                        if (intParsed)
                        {
                            return ((int)value) != parsedValue;
                        }
                        else
                        {
                            if (doubleParsed)
                            {
                                return ((int)value) != parsedDoubleValue;
                            }
                            else
                            {
                                return true;
                            }
                        }
                    default :
                        throw new NotImplementedException(Utils.ErrorMessagePrefix + "We don't know how to handle that type of comparison in PropertyCondition.CheckCondition.");
                }
            }
            else if (valueType.Equals(typeof(double)))
            {
                // To ensure we're comparing apples to apples, convert value to string and then back to a double
                double currentValue = Double.Parse(value.ToString());

                // try to parse m_stringValue
                double parsedValue;
                
                bool doubleParsed = double.TryParse(m_stringValue, out parsedValue);
                
                switch (m_condition)
                {
                    case ConditionType.EQUALS:
                        if (doubleParsed)
                        {
                            return currentValue == parsedValue;
                        }
                        else
                        {
                            return false;
                        }

                    case ConditionType.GREATERTHAN:
                        if (doubleParsed)
                        {
                            return currentValue > parsedValue;
                        }
                        else
                        {
                            return false;
                        }
                    case ConditionType.GREATERTHANOREQUAL:
                        if (doubleParsed)
                        {
                            return currentValue >= parsedValue;
                        }
                        else
                        {
                            return false;
                        }
                    case ConditionType.LESSTHAN:
                        if (doubleParsed)
                        {
                            return currentValue < parsedValue;
                        }
                        else
                        {
                            return false;
                        }
                    case ConditionType.LESSTHANOREQUAL:
                        if (doubleParsed)
                        {
                            return currentValue <= parsedValue;
                        }
                        else
                        {
                            return false;
                        }
                    case ConditionType.NOTEQUALS:
                        if (doubleParsed)
                        {
                            return currentValue != parsedValue;
                        }
                        else
                        {
                            return true;
                        }
                    default:
                        throw new NotImplementedException(Utils.ErrorMessagePrefix + "We don't know how to handle that type of comparison in PropertyCondition.CheckCondition().");
                }
            }
            else
                throw new NotImplementedException(Utils.ErrorMessagePrefix + "We don't know how to handle values of type '" + valueType.FullName + "' from GetValue in PropertyCondition.CheckCondition().");
        }
    }
}